package org.terrier.matching.models;

//import org.terrier.matching.models.MyModelPreParing.*;
//import java.util.Array;

public class LognormalModel extends WeightingModel {
	private static final long serialVersionUID = 1L; 
	double mu = 6.2;  
	double sigma =  mu *20;
    double pi = Math.PI;
    
    //double lambda = 0.71;//1.9418
    double a = 0.95;
    
    double ave_L = this.averageDocumentLength;
    double mu_logL = 4.9974;
    double var_logL = 1.63096;
    double smoothL = 6.5;
    double Gammapart = getGamaPart(a,c);

	public final String getInfo() {
		return "LognormalModel_" + c+"_" + smoothL;
		//return "chisquare_" + "8.4";
		//return "x";
	}
/*	public void setPatameter(double[][] parameterStore)
	{
		int len = parameterStore[0].length;
		double sigmaSorted[] = new double[len];
		int keyIndex = len / 2;//this is the 2-quarytile
		for(int i = 0;i < len;i++)
		{
			mu += parameterStore[0][i];
			sigmaSorted[i] = parameterStore[1][i];
		}
		mu = mu / len;
	    Arrays.sort(sigmaSorted);
		sigma = sigmaSorted[keyIndex];
	}*/
	public double score(double tf, double docLength) {
		/*
		 * Beta
		 */
/*		double prob = a * Math.pow(tf, a - 1);
		double inf1 = -(Math.log(prob)/Math.log(2));
		double inf2 = 1 / (1 + tf);*/
		/*
		 * Gamma
		 */
/*		double logprobGamma =  Gammapart + (a - 1) * Math.log(tf) - lambda * tf;
		double prob = Math.exp(logprobGamma);
		double inf1 = -(Math.log(prob)/Math.log(2));
		double inf2 = 1 / (1 + tf);*/
		
		
		/*
		 * exponential
		 */
		
			
		double x = Math.log(tf);
		double prob = c * Math.exp(- c * x);
		double inf1 = -(Math.log(prob)/Math.log(2));
		double inf2 = 1 / (1 + x);
		
		


		/*
		 * normal after normalization
		 */
/*		double x = Math.log(tf * Math.pow(docLength,1/3));
		double inf1 = 0;
		x = (x - mu);
		double prob = (1 / (Math.sqrt(2 * pi))) * Math.exp(-(x * x) / (2*sigma*sigma));
		//prob = Math.abs(prob);
		if(prob > 0)
		inf1 = -(Math.log(prob)/Math.log(2));
		double inf2 = Math.exp(Math.abs(x)) / Math.pow((1 + Math.exp(Math.abs(x))),1.5);*/
		/*
		 * lognormal
		 */	
/*            double score = 0;
            double x = 0;
            x = tf * docLength - Math.exp(mu);
            score = (1 / (Math.sqrt(2 * pi) * x *  sigma)) * Math.exp(-((Math.log(x)) * (Math.log(x))) / (2 * sigma * sigma));
            //score = (1 / (Math.sqrt(2 * pi) *  sigma)) * Math.exp(-((x - mu) * (x - mu)) / (2 * sigma * sigma));
            //score =     0.0733* Math.pow(x, 1.9) * Math.exp(-(x / 2)); 
            double inf1 = -(Math.log(score)/Math.log(2));
            double inf2 = 1 / (1 + Math.log(x));*/
		/*
		 * normalization
		 */
		double lx = Math.log(docLength);
		double stdNorm = (lx - mu_logL)/Math.sqrt(var_logL);
		double NormNi = Ni(stdNorm);
		double Linf = (NormNi + smoothL)/(1 + smoothL);
		
        return inf1 * inf2 * Linf;
	}
	public double score(//useless here
			double tf,
			double docLength,
			double n_t,
			double F_t,
			double keyFrequency) {
		    return 1d;
		}
	public double getParameter() {//useless here
          double Parameter = sigma;
	    return Parameter;
       }
	/*
	 * get part value of the for gamma(a,lambda) log(gamma),a * log(lambda) - log(gamma(a))
	 */
	public double getGamaPart(double a,double lambda){
		return a * Math.log(lambda) - getLogGammaFunc(a);
	}
	public double getLogGammaFunc(double a){
	
	double[] LogGamma = {4.5995,3.9008,3.4900,3.1971,2.9689,2.7817,2.6228,2.4846,2.3624,2.2527,2.1532,2.0622,1.9783,1.9004,1.8278,1.7598,1.6958,1.6355,1.5783,1.5241,1.4724,1.4232,1.3762,1.3312,1.2880,1.2466,1.2068,1.1684,1.1314,1.0958,1.0614,1.0281,0.9959,0.9648,0.9346,0.9053,0.8769,0.8494,0.8227,0.7967,0.7714,0.7469,0.7230,0.6997,0.6771,0.6550,0.6336,0.6126,0.5922,0.5724,0.5530,0.5341,0.5156,0.4976,0.4800,0.4629,0.4461,0.4298,0.4138,0.3982,0.3830,0.3681,0.3536,0.3394,0.3256,0.3120,0.2988,0.2858,0.2732,0.2609,0.2488,0.2370,0.2255,0.2143,0.2033,0.1925,0.1821,0.1718,0.1618,0.1521,0.1425,0.1332,0.1241,0.1153,0.1066,0.0981,0.0899,0.0819,0.0740,0.0664,0.0589,0.0517,0.0446,0.0377,0.0310,0.0244,0.0181,0.0119,0.0059,0.0000};
	return LogGamma[(int)a * 100];
	}
	/*
	 * made by others
	 */
	 private static double Fi_erf_6(double x){
		 double a=Math.abs(x);
		 return 0.5*(1+erf_6(a/Math.sqrt(2)));
	 }
	 /**
	  * 
	  */
	 private static double erf_6(double x){
		double a[]={0.070523084,0.0422820123,0.0092705272,0.0001520143,0.0002765672,0.0000430638};
		double t=0;
		for(int i=0;i<6;i++){
			t=t+a[i]*Math.pow(x, i+1);
		}
		return 1-Math.pow(1+t, -16);
	 }
	 /**
	  * 
	  */
	 public static double Ni(double x){
		 x = -x;
		 return x==0?0.5:(x>0?Fi_erf_6(x):1-Fi_erf_6(x));
	 }
	 
}
